/* 
Scenic Graphics Library
Copyright (C) 2007 Jouni Tulkki

This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USApackage scenic;
*/

package scenic.path;

import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;

/**
 * This is the base class for all curved segments.
 */
public abstract class CurvedSegment implements Segment {

	protected CurvedSegment() {
	}

	public void walk(PathWalker walker, Point2D.Double position, 
			AffineTransform errorMatrix, double error) {
		Point2D.Double p1 = position;
		Point2D.Double p2 = calcPoint(1.0, position);
		
		iterate(walker, position, errorMatrix, error, 0.0, p1, 1.0, p2);
		position.x = p2.x;
		position.y = p2.y;
	}

	private void iterate(PathWalker walker, Point2D.Double position, 
			AffineTransform errorMatrix, double error,
			double t1, Point2D.Double p1, double t2, Point2D.Double p2) {
		double tc = (t1 + t2) / 2.0;
		Point2D.Double pc = calcPoint(tc, position);
		double ex, ey, tex, tey;
			
		ex = pc.x - (p1.x + p2.x) / 2.0;
		ey = pc.y - (p1.y + p2.y) / 2.0;
		tex = errorMatrix.getScaleX() * ex + errorMatrix.getShearX() * ey;
		tey = errorMatrix.getShearY() * ex + errorMatrix.getScaleY() * ey;
		if(tex * tex + tey * tey >= error * error) {
			iterate(walker, position, errorMatrix, error, t1, p1, tc, pc);
			iterate(walker, position, errorMatrix, error, tc, pc, t2, p2);
		} else {
			walker.lineTo(p2.x, p2.y);
		}
	}
	
	/**
	 * Calculates the position of the segment at the given t value. 
	 * 
	 * @param t the t value (must be in the range [0, 1]).
	 * @param position the previous position.
	 * @return the position.
	 */
	public abstract Point2D.Double calcPoint(double t, Point2D.Double position);
}
